#include <chrono>
#include <exception>
// #include <variant>
#include <deque>
#include <queue>
#include <coroutine>
#include <thread>
#include "../co_async/steps/co_async/debug.hpp"

using namespace std::chrono_literals;

struct PreviousAwaiter {
    std::coroutine_handle<> mPrevious = nullptr;

    constexpr bool await_ready() const noexcept { return false; }

    constexpr std::coroutine_handle<> await_suspend(std::coroutine_handle<> coroutine) const noexcept {
        if(mPrevious){
            return mPrevious;
        }
        else{
            return std::noop_coroutine();
        }
    }

    constexpr void await_resume() const noexcept {}
};

template<class T>
struct Promise {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";
        
        mException = std::current_exception();
    }

    void return_value(T ret) {
        new (&mResult) T(std::move(ret));
    }

    auto yield_value(T ret) {
        new (&mResult) T(std::move(ret));
        return std::suspend_always();
    }

    // 返回引用，这样外面就可以将result移动出去。（而不是拷贝？）
    T result() {
        if (mException) [[unlikely]]{
            std::rethrow_exception(mException);
        }
        T ret = std::move(mResult);
        mResult.~T();
        return ret;
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious = nullptr;
    std::exception_ptr mException{};
    // 小寄巧：包一层union就不会初始化了。
    union {
        T mResult;
    };
    Promise() noexcept {}
    Promise(Promise &&) = delete;
    ~Promise() {}
};

template<>
struct Promise<void> {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept { 
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";
        mException = std::current_exception();
    }

    void return_void() {
    }

    void result() {
        if(mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious = nullptr;

    // 返回值
    std::exception_ptr mException{};

    Promise() = default;
    Promise(Promise &&) = delete;
    ~Promise() = default;
};

template<class T>
struct Task{
    using promise_type = Promise<T>;

    Task(std::coroutine_handle<promise_type> coroutine)
        : mCoroutine(coroutine){}

    // 为什么说根据“三无法则”就要写这一行？移动构造？
    Task(Task &&) = delete;

    ~Task() {
        mCoroutine.destroy();
    }

    struct Awaiter{
        bool await_ready() const noexcept { return false; }

        std::coroutine_handle<> await_suspend(std::coroutine_handle<> coroutine) const noexcept {
            mCoroutine.promise().mPrevious = coroutine;

            return mCoroutine;
        }

        // 返回协程co_return的返回值值。
        T await_resume() const noexcept { return mCoroutine.promise().result(); }

        std::coroutine_handle<promise_type> mCoroutine;
    };

    auto operator co_await() {
        return Awaiter(mCoroutine);
    }

    operator std::coroutine_handle<>() const noexcept {
        return mCoroutine;
    }

    std::coroutine_handle<promise_type> mCoroutine;
};

// 调度器
struct Loop {
    std::deque<std::coroutine_handle<>> mReadyQueue;
    // std::deque<std::coroutine_handle<>> mWaitingQueue;

    struct TimerEntry{
        std::chrono::system_clock::time_point expireTime;
        std::coroutine_handle<> coroutine;
        // 重载<运算符，与大顶堆配合使用
        bool operator<(TimerEntry const & that) const noexcept{
            return expireTime > that.expireTime;
        }
    };

    // std::deque<TimerEntry> timerTable;
    // 大顶堆，top返回最大的值
    std::priority_queue<TimerEntry> mTimerHeap;

    void addTask(std::coroutine_handle<> t) {
        mReadyQueue.push_front(t);
    }

    void addTimer(std::chrono::system_clock::time_point expireTime, std::coroutine_handle<> t){
        // timerTable.push_front({expireTime, t});
        // O(nlog(n)) 复杂度挺差的。
        // std::sort(timerTable.begin(), timerTable.end());
        mTimerHeap.push({expireTime, t});
    }

    void runAll() {
        while(!mTimerHeap.empty() || !mReadyQueue.empty()){
            while(!mReadyQueue.empty()) {
                auto readyTask = mReadyQueue.front();
                mReadyQueue.pop_front();
                readyTask.resume();
            }
            if(!mTimerHeap.empty()){
                auto nowTime = std::chrono::system_clock::now();
                auto timer = std::move(mTimerHeap.top());
                if(timer.expireTime<nowTime){
                    mTimerHeap.pop();
                    mReadyQueue.push_back(timer.coroutine);
                    continue;
                }
                else {
                    // 如果一直没有任务等待超时，那么进程就睡眠，直到某个协程睡醒了
                    // 这样能够减少CPU利用率。
                    std::this_thread::sleep_until(timer.expireTime);
                }
            }
        }
    }

    // 为了防止一不小心拷贝了。
    // 所以把移动赋值删了，这样其他的构造函数也都默认删了（但是保留默认构造）。
    Loop &operator=(Loop &&) = delete;
};

Loop &getLoop() {
    // loop作为全局变量，只会构造一次（单例模式）
    static Loop loop;
    return loop;
}

struct SleepAwaiter {
    bool await_ready() const {
        return std::chrono::system_clock::now() >= mExpireTime;
    }

    std::coroutine_handle<> await_suspend(std::coroutine_handle<> coroutine) const {
        // std::this_thread::sleep_until(mExpireTime);
        // return coroutine;
        getLoop().addTimer(mExpireTime, coroutine);
        return std::noop_coroutine();
    }

    void await_resume() const noexcept {}

    std::chrono::system_clock::time_point mExpireTime;
};

Task<void> sleep_until(std::chrono::system_clock::time_point expireTime) {
    co_await SleepAwaiter(expireTime);
    co_return;
}

Task<void> sleep_for(std::chrono::system_clock::duration duration) {
    co_await SleepAwaiter(std::chrono::system_clock::now() + duration);
    co_return;
}

Task<int> hello1() {
    debug(), "hello begin to sleep 1s";
    co_await sleep_for(1s); // 1s 等价于 std::chrono::seconds(1)
    debug(), "hello had sleep 1s done";
    co_return 42;
}

Task<int> hello2() {
    debug(), "hello begin to sleep 2s";
    co_await sleep_for(2s); // 1s 等价于 std::chrono::seconds(1)
    debug(), "hello had sleep 2s done";
    co_return 42;
}

int main(){
    auto t1 = hello1();
    auto t2 = hello2();
    Loop loop;
    getLoop().addTask(t1);
    getLoop().addTask(t2);
    getLoop().runAll();
    debug(), "t1 主函数中得到的hello结果：", t1.mCoroutine.promise().result();
    debug(), "t2 主函数中得到的hello结果：", t2.mCoroutine.promise().result();
    return 0;
}